/*  SDS / SCL direct coupling */

#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#ifndef DOUBLE_PRECISION
#define DOUBLE_PRECISION
#endif
#include "cfort.h"

#include "sds_proto.h"
#include "sds_size.h"

static struct tagDB_SDB * db = NULL ;

static char Err[255],HeadTitle[255];
static char *SDA_FileName;

static Real FormerTimeStep = 0.;

#if defined(CPL_LIB_SDS)
#define Execute(a) {int Error= SDE ## a; /*printf("%s\n",# a);*/   \
if (Error==0) {SDEGetErrorMessageString(db,Err,HeadTitle);\
printf("MOTION : %s %s\n",HeadTitle,Err);exit(-1);} ;}
#else
#define Execute(a) {printf("Error : MOTION coupling unavailable\n");exit(-1);}
#endif

extern char* pcstrdup(char*);

extern void SDS_ERROR(Fchar Addlength(int));

void FortranName(SDS_INIT,sds_init)
    ( int *NumberOfFlexibleParts, int *NumberOfReferenceParts,
     Real *InitialFlexibleValues,Real *InitialReferenceValues,
         Fchar FP, Fchar RP, Fchar FN
         AddLength(int FPL) AddLength(int RPL) AddLength(int FNL))
{
Character FileName,FlexibleParts,ReferenceParts;
char *SDS_FileName,*SDS_ReferenceParts,*SDS_FlexibleParts;
int i;
FileName      =character(CharPointer(FN),CharLength(FN,FNL));
FlexibleParts =character(CharPointer(FP),CharLength(FP,FPL));
ReferenceParts=character(CharPointer(RP),CharLength(RP,RPL));
if (FlexibleParts.length!=SDS_SIZE||ReferenceParts.length!=SDS_SIZE)
{printf("C-Fortran interface error\nPlease contact C3P\n");exit(-1);}

#define ALLOC(type,pointer,length) \
   pointer=(type *) malloc(length*sizeof(type))

ALLOC(char,SDS_FileName,SDS_FILENAME_SIZE+1);
ALLOC(char,SDS_ReferenceParts,*NumberOfReferenceParts*(SDS_SIZE+1));
ALLOC(char,SDS_FlexibleParts ,*NumberOfFlexibleParts *(SDS_SIZE+1));

fortc_string(SDS_FileName,FileName.pointer,SDS_FILENAME_SIZE);
SDA_FileName=pcstrdup(SDS_FileName);
SDA_FileName[strlen(SDS_FileName)-1]='a';

for (i=0;i<*NumberOfReferenceParts;i++)
     fortc_string(SDS_ReferenceParts+(SDS_SIZE+1)*i,
                      ReferenceParts.pointer+SDS_SIZE*i,SDS_SIZE);

for (i=0;i<*NumberOfFlexibleParts;i++)
     fortc_string(SDS_FlexibleParts+(SDS_SIZE+1)*i,
                      FlexibleParts.pointer+SDS_SIZE*i,SDS_SIZE);

Execute(InitEngineDatabase(&db));

Execute(LoadEngineDatabase(db, SDS_FileName));
/* Determination of initial velocities for the flexible parts */
Execute(DefineReferenceBodies(db,SDS_FlexibleParts ,*NumberOfFlexibleParts));

Execute(EngineCompile(db));
Execute(GetDynamicResults(db,InitialFlexibleValues));

/* Definition of the system used for the computation */
Execute(DefineFlexibleBodies (db,SDS_FlexibleParts ,*NumberOfFlexibleParts));
Execute(DefineReferenceBodies(db,SDS_ReferenceParts,*NumberOfReferenceParts));
Execute(EngineCompile(db));
Execute(GetDynamicResults(db,InitialReferenceValues));
}

void FortranName(SDS_STEP,sds_step)(Real *ReferenceForcesValues,
                                    Real *TimeStep)
{
FormerTimeStep=*TimeStep;

Execute(EngineRunOneStep(db,*TimeStep,ReferenceForcesValues));
}

void FortranName(SDS_POSVEL,sds_posvel)(Real *ReferenceValues)
{
Execute(GetDynamicResults(db,ReferenceValues));
}

void FortranName(SDS_OUTPUT,sds_output)(int *save_sda)
{
if (FormerTimeStep!=0) Execute(EnginePrintResult(db));
#if defined(CPL_LIB_SDS)
/* Merge of all SDS output files in one SDA file (different at each call) */
if (*save_sda)  SDESaveSDASimulation( db, SDA_FileName ); 
#endif
}

void FortranName(SDS_END,sds_end)()
{
Execute(EnginePrintResult(db));
Execute(EngineEndRun(db));
}
